﻿using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AutoMapper;
using SW.DDD.Domain;
using SW.DDD.Infrastructure;

namespace SW.DDD.Application.Query
{
    public class SubsQueryHandler<TView, TSubEntity, TAggregateRoot, TKey> :
        IQueryHandler<SubsQuery<TView, TSubEntity, TAggregateRoot, TKey>, (IEnumerable<TView> data, int? count)>
        where TAggregateRoot : class, IAggregateRoot<TKey>
        where TKey : notnull
    {
        protected IRepository<TAggregateRoot, TKey> Repository { get; }

        protected IMapper Mapper { get; }

        public SubsQueryHandler(IRepository<TAggregateRoot, TKey> repository, IMapper mapper)
        {
            Repository = repository;
            Mapper = mapper;
        }

        public async Task<(IEnumerable<TView> data, int? count)> Handle(
            SubsQuery<TView, TSubEntity, TAggregateRoot, TKey> request, 
            CancellationToken cancellationToken)
        {
            var result = await Repository.QueryAsync(qy =>
            {
                var subs = qy.Where(e => e.Id.Equals(request.Id))
                             .SelectMany(request.SubsSelector);
                var views = Mapper.ProjectTo<TView>(subs, request.Parameters);
                return request.QueryExpression.ExecuteQuery(views);
            });

            if(!request.NeedCount)
                return (result, null);
            else
            {
                var count = await Repository.CountAsync(qy =>
                {
                    var subs = qy.Where(e => e.Id.Equals(request.Id))
                                 .SelectMany(request.SubsSelector);
                    var views = Mapper.ProjectTo<TView>(subs, request.Parameters);
                    return request.QueryExpression.ExecuteWhere(views);
                });
                return (result, count);
            }
        }
    }
}
